package com.iot.gateway.aspectj;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.iot.gateway.annotation.FieldConverter;
import com.iot.gateway.annotation.FieldMapping;
import com.iot.gateway.aspectj.converter.StringToIntegerConverter;
import com.iot.gateway.aspectj.converter.TimestampConverter;
import com.iot.gateway.utils.serializer.DataSerializer;
import com.iot.gateway.utils.serializer.JsonSerializer;
import com.iot.gateway.utils.serializer.TopicSerializer;
import com.iot.gateway.utils.serializer.XmlSerializer;
import lombok.Data;

import java.lang.reflect.Field;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 数据解析器
 */
public class IoTFieldUtil {

    private static final ObjectMapper jsonMapper = new ObjectMapper();

    public static <T> T map(Map<String, Object> source, Class<T> targetClass) throws Exception {
        T target = targetClass.getDeclaredConstructor().newInstance();
        Map<String, Field> targetFields = getAnnotatedFields(targetClass);
        for (Map.Entry<String, Object> entry : source.entrySet()) {
            String sourceKey = entry.getKey();
            Object value = entry.getValue();
            // 查找匹配的目标字段
            Field targetField = findMappedField(sourceKey, targetFields);
            if (targetField != null) {
                value = convertValue(value, targetField);
                setFieldValue(target, targetField, value);
            }
        }
        return target;
    }

    private static Map<String, Field> getAnnotatedFields(Class<?> clazz) {
        Map<String, Field> fields = new HashMap<>();
        for (Field field : clazz.getDeclaredFields()) {
            if (field.isAnnotationPresent(FieldMapping.class)) {
                FieldMapping mapping = field.getAnnotation(FieldMapping.class);
                fields.put(mapping.source(), field);
            }
        }
        return fields;
    }

    private static Field findMappedField(String sourceKey, Map<String, Field> fields) {
        // 支持直接匹配和忽略大小写的匹配
        return fields.getOrDefault(sourceKey.toLowerCase(), fields.entrySet().stream().filter(e -> e.getKey().equalsIgnoreCase(sourceKey)).map(Map.Entry::getValue).findFirst().orElse(null));
    }

    private static Object convertValue(Object value, Field field) throws Exception {
        FieldMapping mapping = field.getAnnotation(FieldMapping.class);
        FieldConverter converter = mapping.converter().getDeclaredConstructor().newInstance();
        return converter.convert(value);
    }

    private static void setFieldValue(Object target, Field field, Object value) throws Exception {
        field.setAccessible(true);
        field.set(target, value);
    }

    /**
     * 格式化输出方法
     * @param data 数据
     * @param serializer 序列化
     * @return 格式化输出方法
     */
    public static <T> String formatOutput(T data, DataSerializer<T> serializer) throws Exception {
        return serializer.serialize(data);
    }

    @Data
    static
    class DeviceData {
        @FieldMapping(source = "device_id", target = "deviceId")
        private String deviceId;

        @FieldMapping(source = "temp", target = "temperature", converter = StringToIntegerConverter.class)
        private int temperature;

        @FieldMapping(source = "timestamp", converter = TimestampConverter.class)
        private Date timestamp;

    }

    @Data
    static
    class TargetData {

        @FieldMapping(source = "device_id")
        private String deviceId;

        @FieldMapping(source = "temp", converter = StringToIntegerConverter.class)
        private int temperature;

        @FieldMapping(source = "timestamp", converter = TimestampConverter.class)
        private String timestamp;
    }

    // 测试使用
    public static void main(String[] args) throws Exception {
        Map<String, Object> rawData = new HashMap<>();
        rawData.put("device_id", "sensor_001");
        rawData.put("temp", "25");
        rawData.put("timestamp", System.currentTimeMillis());
        IoTFieldUtil.TargetData data = IoTFieldUtil.map(rawData, IoTFieldUtil.TargetData.class);
        // JSON格式输出
        String json = formatOutput(data, new JsonSerializer<>());
        System.out.println("JSON Output:\n" + json);

        // XML格式输出
        String xml = formatOutput(data, new XmlSerializer<>());
        System.out.println("\nXML Output:\n" + xml);

        // Topic格式输出（示例模板）
        TopicSerializer<TargetData> topicSerializer =
                new TopicSerializer<>("/devices/{deviceId}/datapoints/{timestamp}");
        String topic = formatOutput(data, topicSerializer);
        System.out.println("\nTopic Output:\n" + topic);
    }

}
